{
  "version": "1.4",
  "metadata": {
    "app": "nytem-2021/appland",
    "language": {
      "name": "ruby",
      "engine": "ruby",
      "version": "2.6.6"
    },
    "client": {
      "name": "appmap",
      "url": "https://github.com/applandinc/appmap-ruby",
      "version": "0.42.0"
    },
    "frameworks": [
      {
        "name": "rails",
        "version": "5.2.4.2"
      },
      {
        "name": "rspec",
        "version": "3.9.1"
      }
    ],
    "git": {
      "repository": "git@github.com:applandinc/appland.git",
      "branch": "swagger",
      "commit": "8133d5f99aba206c6ae46645d02624360decba7a",
      "status": [
        "M swagger/openapi.yaml",
        "?? 20210310072459.appmap.json"
      ],
      "git_last_annotated_tag": null,
      "git_last_tag": "v0.22.0",
      "git_commits_since_last_annotated_tag": null,
      "git_commits_since_last_tag": 0
    },
    "name": "API::APIKeysController revoke an existing api key",
    "source_location": "spec/requests/api_api_keys_spec.rb",
    "recorder": {
      "name": "rspec"
    },
    "fingerprints": [
      {
        "appmap_digest": "bec8acd10dd0bd49fd510724c4277d1ce9758641d5aefa1be2d3479bc4e26573",
        "canonicalization_algorithm": "info_v1",
        "digest": "546cfeae6dc0f341b028dd4ae0eb45b07421e883dd6ac6d191cf349880aadaa0",
        "fingerprint_algorithm": "sha256"
      },
      {
        "appmap_digest": "bec8acd10dd0bd49fd510724c4277d1ce9758641d5aefa1be2d3479bc4e26573",
        "canonicalization_algorithm": "update_v1",
        "digest": "ef19c6dac44d3bf3bd3e35495b3ac9f529e7088c9735810e5ab36c624790666a",
        "fingerprint_algorithm": "sha256"
      },
      {
        "appmap_digest": "bec8acd10dd0bd49fd510724c4277d1ce9758641d5aefa1be2d3479bc4e26573",
        "canonicalization_algorithm": "trace_v1",
        "digest": "050c069ece1a6860d8bf13b496f4241fe14bbb568d042842372159c9f9b0f7b4",
        "fingerprint_algorithm": "sha256"
      }
    ]
  },
  "classMap": [
    {
      "name": "app/models",
      "type": "package",
      "children": [
        {
          "name": "ApiKey",
          "type": "class",
          "children": [
            {
              "name": "issue",
              "type": "function",
              "location": "app/models/api_key.rb:28",
              "static": true,
              "source": "    def issue(login, description: nil, encode: true)\n      api_key = DAO::ApiKey.new.tap do |api_key|\n        api_key.login = login\n        api_key.description = description if description.present?\n        api_key.save\n      end\n\n      return encode(api_key) if encode\n\n      api_key\n    end\n"
            },
            {
              "name": "encode",
              "type": "function",
              "location": "app/models/api_key.rb:20",
              "static": true,
              "source": "    def encode(api_key)\n      Base64.urlsafe_encode64([api_key.login, api_key.key].join(SEPARATOR), padding: false)\n    end\n"
            },
            {
              "name": "authenticate",
              "type": "function",
              "location": "app/models/api_key.rb:52",
              "static": true,
              "labels": [
                "provider.authentication"
              ],
              "comment": "# @labels provider.authentication\n",
              "source": "    def authenticate(api_key)\n      login, key = decode(api_key)\n      result = DAO::ApiKey.where(login: login).match(key)\n\n      if result.present?\n        touch(result)\n        User::Show.new(result.user)\n      else\n        nil\n      end\n    end\n"
            },
            {
              "name": "decode",
              "type": "function",
              "location": "app/models/api_key.rb:24",
              "static": true,
              "source": "    def decode(api_key)\n      Base64.urlsafe_decode64(api_key).split(SEPARATOR)\n    end\n"
            },
            {
              "name": "touch",
              "type": "function",
              "location": "app/models/api_key.rb:11",
              "static": true,
              "source": "    def touch(api_key)\n      if api_key.last_used.nil? || api_key.last_used > 15.minutes.ago\n        api_key.last_used = Time.now\n        api_key.save_changes\n      end\n\n      api_key\n    end\n"
            },
            {
              "name": "revoke",
              "type": "function",
              "location": "app/models/api_key.rb:40",
              "static": true,
              "source": "    def revoke(api_key)\n      login, key = decode(api_key)\n      DAO::ApiKey.where(login: login).match(key)&.destroy\n    end\n"
            }
          ]
        }
      ]
    },
    {
      "name": "action_pack",
      "type": "package",
      "children": [
        {
          "name": "ActionDispatch",
          "type": "class",
          "children": [
            {
              "name": "Cookies",
              "type": "class",
              "children": [
                {
                  "name": "CookieJar",
                  "type": "class",
                  "children": [
                    {
                      "name": "update",
                      "type": "function",
                      "location": "/Users/kgilpin/tmp/appland/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.4.2/lib/action_dispatch/middleware/cookies.rb:344",
                      "static": false,
                      "labels": [
                        "provider.http.cookie"
                      ],
                      "source": "      def update(other_hash)\n        @cookies.update other_hash.stringify_keys\n        self\n      end\n"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "name": "app/controllers",
      "type": "package",
      "children": [
        {
          "name": "API",
          "type": "class",
          "children": [
            {
              "name": "APIKeysController",
              "type": "class",
              "children": [
                {
                  "name": "destroy",
                  "type": "function",
                  "location": "app/controllers/api/api_keys_controller.rb:15",
                  "static": false,
                  "source": "    def destroy\n      if ApiKey.revoke(@api_key)\n        render json: '', status: :no_content\n      else\n        render json: '', status: :unauthorized\n      end\n    end\n"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "name": "json",
      "type": "package",
      "children": [
        {
          "name": "JSON",
          "type": "class",
          "children": [
            {
              "name": "Ext",
              "type": "class",
              "children": [
                {
                  "name": "Generator",
                  "type": "class",
                  "children": [
                    {
                      "name": "State",
                      "type": "class",
                      "children": [
                        {
                          "name": "generate",
                          "type": "function",
                          "location": "JSON::Ext::Generator::State#generate",
                          "static": false,
                          "labels": [
                            "format.json",
                            "provider.serialization"
                          ]
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "events": [
    {
      "id": 26643,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "issue",
      "path": "app/models/api_key.rb",
      "lineno": 28,
      "static": true,
      "parameters": [
        {
          "name": "login",
          "class": "String",
          "object_id": 70146237309120,
          "value": "admin",
          "kind": "req"
        },
        {
          "name": "description",
          "class": "String",
          "object_id": 70145697080380,
          "value": "example api key",
          "kind": "key"
        },
        {
          "name": "encode",
          "class": "NilClass",
          "object_id": 8,
          "value": null,
          "kind": "key"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26644,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "INSERT INTO \"api_keys\" (\"login\", \"description\") VALUES ('admin', 'example api key') RETURNING *",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26645,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26644,
      "elapsed": 0.001692
    },
    {
      "id": 26646,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "encode",
      "path": "app/models/api_key.rb",
      "lineno": 20,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "DAO::ApiKey",
          "object_id": 70145861792520,
          "value": "#<DAO::ApiKey:0x00007f9836596610>",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26647,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26646,
      "elapsed": 0.000038,
      "return_value": {
        "class": "String",
        "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
        "object_id": 70145695541220
      }
    },
    {
      "id": 26648,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26643,
      "elapsed": 0.006656,
      "return_value": {
        "class": "String",
        "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
        "object_id": 70145695541220
      }
    },
    {
      "id": 26649,
      "event": "call",
      "thread_id": 70146500788180,
      "http_server_request": {
        "request_method": "DELETE",
        "path_info": "/api/api_keys",
        "mime_type": "application/x-www-form-urlencoded",
        "normalized_path_info": "/api/api_keys(.:format)",
        "authorization": "Bearer YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0"
      },
      "message": [
        {
          "name": "controller",
          "class": "String",
          "value": "api/api_keys",
          "object_id": 70145861067500
        },
        {
          "name": "action",
          "class": "String",
          "value": "destroy",
          "object_id": 70146368021480
        }
      ]
    },
    {
      "id": 26650,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ActionDispatch::Cookies::CookieJar",
      "method_id": "update",
      "path": "/Users/kgilpin/tmp/appland/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.4.2/lib/action_dispatch/middleware/cookies.rb",
      "lineno": 344,
      "static": false,
      "parameters": [
        {
          "name": "other_hash",
          "class": "Hash",
          "object_id": 70145695556340,
          "value": "{}",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "ActionDispatch::Cookies::CookieJar",
        "object_id": 70145695709840,
        "value": "#<ActionDispatch::Cookies::CookieJar:0x00007f98228cf520>"
      }
    },
    {
      "id": 26651,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26650,
      "elapsed": 0.00001,
      "return_value": {
        "class": "ActionDispatch::Cookies::CookieJar",
        "value": "#<ActionDispatch::Cookies::CookieJar:0x00007f98228cf520>",
        "object_id": 70145695709840
      }
    },
    {
      "id": 26652,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "authenticate",
      "path": "app/models/api_key.rb",
      "lineno": 52,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146232811420,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26653,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "decode",
      "path": "app/models/api_key.rb",
      "lineno": 24,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146232811420,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26654,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26653,
      "elapsed": 0.000015,
      "return_value": {
        "class": "Array",
        "value": "[\"admin\", \"622a15f0-f11d-436f-8c17-6cf0c5af7ab4\"]",
        "object_id": 70146232819480
      }
    },
    {
      "id": 26655,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26656,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26655,
      "elapsed": 0.001296
    },
    {
      "id": 26657,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "touch",
      "path": "app/models/api_key.rb",
      "lineno": 11,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "DAO::ApiKey",
          "object_id": 70145696542440,
          "value": "#<DAO::ApiKey:0x00007f9822a65dd0>",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26658,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "UPDATE \"api_keys\" SET \"last_used\" = '2021-03-26 20:32:37.198051+0000' WHERE (\"id\" = 1)",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26659,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26658,
      "elapsed": 0.001255
    },
    {
      "id": 26660,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26657,
      "elapsed": 0.007685,
      "return_value": {
        "class": "DAO::ApiKey",
        "value": "#<DAO::ApiKey:0x00007f9822a65dd0>",
        "object_id": 70145696542440
      }
    },
    {
      "id": 26661,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "SELECT * FROM \"users\" WHERE (\"users\".\"login\" = 'admin') LIMIT 1",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26662,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26661,
      "elapsed": 0.001464
    },
    {
      "id": 26663,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26652,
      "elapsed": 0.021127,
      "return_value": {
        "class": "User::Show",
        "value": "#<User::Show:0x00007f9885d774e8>",
        "object_id": 70146528623220
      }
    },
    {
      "id": 26664,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "API::APIKeysController",
      "method_id": "destroy",
      "path": "app/controllers/api/api_keys_controller.rb",
      "lineno": 15,
      "static": false,
      "parameters": [],
      "receiver": {
        "class": "API::APIKeysController",
        "object_id": 70145695591400,
        "value": "#<API::APIKeysController:0x00007f98228957d0>"
      }
    },
    {
      "id": 26665,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "revoke",
      "path": "app/models/api_key.rb",
      "lineno": 40,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146232811420,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26666,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "decode",
      "path": "app/models/api_key.rb",
      "lineno": 24,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146232811420,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26667,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26666,
      "elapsed": 0.000013,
      "return_value": {
        "class": "Array",
        "value": "[\"admin\", \"622a15f0-f11d-436f-8c17-6cf0c5af7ab4\"]",
        "object_id": 70146528618280
      }
    },
    {
      "id": 26668,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26669,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26668,
      "elapsed": 0.001225
    },
    {
      "id": 26670,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "DELETE FROM \"api_keys\" WHERE \"id\" = 1",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26671,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26670,
      "elapsed": 0.001328
    },
    {
      "id": 26672,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26665,
      "elapsed": 0.015355,
      "return_value": {
        "class": "DAO::ApiKey",
        "value": "#<DAO::ApiKey:0x00007f9885fac2e0>",
        "object_id": 70146529780080
      }
    },
    {
      "id": 26673,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26664,
      "elapsed": 0.015768,
      "return_value": {
        "class": "String",
        "value": "",
        "object_id": 70146500618800
      }
    },
    {
      "id": 26674,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26649,
      "elapsed": 0.038182,
      "http_server_response": {
        "status": 204,
        "mime_type": "application/json; charset=utf-8"
      }
    },
    {
      "id": 26675,
      "event": "call",
      "thread_id": 70146500788180,
      "http_server_request": {
        "request_method": "DELETE",
        "path_info": "/api/api_keys",
        "mime_type": "application/x-www-form-urlencoded",
        "normalized_path_info": "/api/api_keys(.:format)",
        "authorization": "Bearer YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0"
      },
      "message": [
        {
          "name": "controller",
          "class": "String",
          "value": "api/api_keys",
          "object_id": 70145861067500
        },
        {
          "name": "action",
          "class": "String",
          "value": "destroy",
          "object_id": 70146368021480
        }
      ]
    },
    {
      "id": 26676,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ActionDispatch::Cookies::CookieJar",
      "method_id": "update",
      "path": "/Users/kgilpin/tmp/appland/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.4.2/lib/action_dispatch/middleware/cookies.rb",
      "lineno": 344,
      "static": false,
      "parameters": [
        {
          "name": "other_hash",
          "class": "Hash",
          "object_id": 70146239974980,
          "value": "{}",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "ActionDispatch::Cookies::CookieJar",
        "object_id": 70146239947800,
        "value": "#<ActionDispatch::Cookies::CookieJar:0x00007f98636dc830>"
      }
    },
    {
      "id": 26677,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26676,
      "elapsed": 0.000009,
      "return_value": {
        "class": "ActionDispatch::Cookies::CookieJar",
        "value": "#<ActionDispatch::Cookies::CookieJar:0x00007f98636dc830>",
        "object_id": 70146239947800
      }
    },
    {
      "id": 26678,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "authenticate",
      "path": "app/models/api_key.rb",
      "lineno": 52,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146239956780,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26679,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "ApiKey",
      "method_id": "decode",
      "path": "app/models/api_key.rb",
      "lineno": 24,
      "static": true,
      "parameters": [
        {
          "name": "api_key",
          "class": "String",
          "object_id": 70146239956780,
          "value": "YWRtaW46NjIyYTE1ZjAtZjExZC00MzZmLThjMTctNmNmMGM1YWY3YWI0",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "Class",
        "object_id": 70145695643300,
        "value": "ApiKey"
      }
    },
    {
      "id": 26680,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26679,
      "elapsed": 0.000014,
      "return_value": {
        "class": "Array",
        "value": "[\"admin\", \"622a15f0-f11d-436f-8c17-6cf0c5af7ab4\"]",
        "object_id": 70146233428240
      }
    },
    {
      "id": 26681,
      "event": "call",
      "thread_id": 70146500788180,
      "sql_query": {
        "sql": "SELECT * FROM \"api_keys\" WHERE (\"login\" = 'admin')",
        "database_type": "postgres",
        "server_version": 120003
      }
    },
    {
      "id": 26682,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26681,
      "elapsed": 0.0014
    },
    {
      "id": 26683,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26678,
      "elapsed": 0.006709
    },
    {
      "id": 26684,
      "event": "call",
      "thread_id": 70146500788180,
      "defined_class": "JSON::Ext::Generator::State",
      "method_id": "generate",
      "path": "JSON::Ext::Generator::State#generate",
      "static": false,
      "parameters": [
        {
          "name": "arg",
          "class": "Hash",
          "object_id": 70146233364200,
          "value": "{\"error\"=>\"must provide authorization\"}",
          "kind": "req"
        }
      ],
      "receiver": {
        "class": "JSON::Ext::Generator::State",
        "object_id": 70146233364040,
        "value": "#<JSON::Ext::Generator::State:0x00007f9862a4dc90>"
      }
    },
    {
      "id": 26685,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26684,
      "elapsed": 0.000028,
      "return_value": {
        "class": "String",
        "value": "{\"error\":\"must provide authorization\"}",
        "object_id": 70146233377000
      }
    },
    {
      "id": 26686,
      "event": "return",
      "thread_id": 70146500788180,
      "parent_id": 26675,
      "elapsed": 0.007931,
      "http_server_response": {
        "status": 401,
        "mime_type": "application/json; charset=utf-8"
      }
    }
  ]
}